/*
 * =====================================================================================
 *
 *       Filename:  sock.h
 *
 *    Description:  封装sock
 *
 *        Version:  1.0
 *        Created:  2008年09月25日 10时09分48秒
 *       Revision:  none
 *       Compiler:  g++
 *
 *         Author:  ZhixiongHong (hzx), fishwarter@gmail.com
 *        Company:  Unioncast
 *
 * =====================================================================================
 */

#ifndef SS_SOCK_H
#define SS_SOCK_H

#ifdef HAS_SS_NAMESPACE
namespace ss{
#endif // HAS_SS_NAMESPACE

class BaseSocket
{
public:
	BaseSocket(int domain, int type, int protocol, int sendBufLen=0, int recvBufLen=0);
	virtual ~BaseSocket();
public:
	/*
	 *	@brief: 绑定端口
	 */
	int bind(const char* host, unsigned short port);

	/*
	 *	@breif: 监听
	 *  @backlog: defines the maximum length the queue of pending connections may grow to
	 */	
	int base_listen(int backlog);

	/*
	 *	@brief: 接受连接	 
	 */		
	int base_accept(SockAddr* pAddr); // todo
	
	int base_connect(const SockAddr& addr);

	/*
	 *	@brief: 非阻塞连接
	 */
	int connect_nb(const SockAddr& addr); 
	/*
	 *	@brief: 发送数据流
	 */
	int base_send(const void *buf, size_t len, int flags=0);

	/*
	 *	@brief: 接受数据流
	 *  @buf: 接受buf，调用前分配空间
	 */
	int base_recv(void *buf, size_t len, int flags=0);

	/*
	 *  @brief: 发送数据包
	 *  @buf: 待发送数据
     *  @len: 数据发送的长度
	 * 	@addr: 发送地址
  	 *  @flags:
	 */
    int base_sendto(const void *buf, size_t len, const SockAddr& addr, int flags = 0);
	
	/*
	 *  @brief: 接受数据包
	 *	@buf: 接受缓冲区，调用之前分配空间
	 */
    int base_recvfrom(void *buf, size_t len, SockAddr* pAddr, int flags = 0);
	
	/*
	 *	@brief: 关闭socket
	 */
	int close();

	int attach(int fd);
	/*
	 *	@brief: 设置socket选项
 	 */
	int setsockopt(int level, int optname, const char* optval, int optlen);

	
	/*
	 * 	@brief: 设置阻塞或者非阻塞的socket
	 */
	int setblock(bool bBlock);
	

	/*
	 * 	@brief: 是否可读，ms, 毫秒,设置超时时间
	 *		   只对阻塞的socket有有意义，所以，在之前需要将socket设置为阻塞的
	 */
	bool is_readable(int ms);
	bool is_writeable(int ms);
	bool is_active(int ms);
	bool is_good(int ms);

	void	setTimeout(int timeout=DEFAULT_TIMEOUT);
private:
	/*
	 * 	@brief: 初始化socket系统
 	 */
	static bool init_sockt_system(); 	
private:
	int			_sockfd;			
	bool		_bBlock; 			// 是否阻塞
	SockAddr	_cliAddr;			// todo
	SockAddr 	_svrAddr;			// todo
	int			_recvBufLen;		// 接受缓冲区的长度
	int			_sendBufLen;		// 发送缓冲区的长度
	int			_timeout;
};


class UDPSocket: public BaseSocket
{
public:
	UDPSocket(int domain=AF_INET, int protocol=0, int sendBufLen=0, int recvBufLen=0);
	~UDPSocket();
public:	
	/*
	 *  @brief: 接受数据包, 在base_recvfrom之上加入超时时间处理
	 *	@buf: 接受缓冲区，调用之前分配空间
	 */
    int recvfrom(void *buf, size_t len, SockAddr* pAddr, int flags = 0);	
	
    int sendto(const void *buf, size_t len, const SockAddr& addr, int flags = 0);
	
	/*
 	 *	@brief: 连接服务器
				1. 阻塞连接，ms=0
				2. 非阻塞连接，ms=value，等待连接可读写的时间
	 */
	int connect(const SockAddr& addr, bool isBlock = true, int ms=0);

private:
};


class TCPSocket: public BaseSocket
{
public:
	TCPSocket(int domain=AF_INET, int protocol=0, int sendBufLen=0, int recvBufLen=0);
	~TCPSocket();
public:
	/*
 	 *	@brief: 连接服务器
				1. 阻塞连接，ms=0
				2. 非阻塞连接，ms=value，等待连接可读写的时间
	 */
	int connect(const SockAddr& addr, bool isBlock = true, int ms=0);
	
	int listen(int backlog);
		
	/*
	 *	@brief: 接受和发送，和BaseSocket相比，加入了select超时操作
	 * 	@return: 接受和发送数据的长度
	 */
	int send(const void *buf, size_t len, int flags=0);
	int recv(void *buf, size_t len, int flags=0);

	/*
	 *	@brief: 保证数据接受和发送定长的数据
	 */
	int safe_send(const void*buf, size_t len, int falgs=0);
	int safe_recv(void *buf, size_t len, int flags=0);
	
	/*
	 *	@brief: 通信采用先发送长度，再发送内容的方式
				在多线程处理中，注意这个地方互斥访问的问题
	 */
	int	send_packet(const void* buf, size_t len, int flags=0);
	int recv_packet(void *buf, size_t len, int flags=0);

	TCPSocket*	accept(int ms = 0);	
private:
};


#ifdef HAS_SS_NAMESPACE
}
#endif // HAS_SS_NAMESPACE

#endif // SS_SOCK_H
